import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ResultUtils } from 'src/common/utils/result.utils';
import { In, Repository } from 'typeorm';
import { Classify } from '../classify/classify.entity';
import { Tag } from '../tag/tag.entity';
import { Article } from './article.entity';
import { CreateArticleDto } from './dto/create-article.dto';
import { GetArticleDto } from './dto/get-article.dto';
import { UpdateArticleDto } from './dto/update-article.dto';

@Injectable()
export class ArticleService {
  constructor(
    @InjectRepository(Article) private articleRepository:Repository<Article>,
    @InjectRepository(Tag) private tagRepository:Repository<Tag>,
    @InjectRepository(Classify) private classifyRepository:Repository<Classify>,
  ){}
  async create(createArticleDto: CreateArticleDto) {
    if(createArticleDto.tags instanceof Array && typeof createArticleDto.tags[0] === 'number') {
      createArticleDto.tags = await this.tagRepository.find({
        where:{
          id:In(createArticleDto.tags as Array<number>)
        }
      });
    }
    if(typeof createArticleDto.classify === 'number') {
      createArticleDto.classify = await this.classifyRepository.findOne({
        where:{id:createArticleDto.classify}
      });
    }
    const article = await this.articleRepository.create(createArticleDto as Partial<Article>);
    const result = await this.articleRepository.save(article);
    const id = result.id;
    return ResultUtils.success(id);
  }

  async findAll(query:GetArticleDto,isAdmin:boolean) {
    let {limit,page,classifyId,sort,title,tagId} = query;
    const queryBuilder = this.articleRepository.createQueryBuilder('article');
    if(!isAdmin) {
      queryBuilder.leftJoinAndSelect('article.tags','tag','tag.status = :status',{status:1})
                  .leftJoinAndSelect('article.classify','classify','classify.status = :status',{status:1})
                  .andWhere('article.status=:status',{status:1});
    }else {
      queryBuilder.leftJoinAndSelect('article.tags','tags')
                  .leftJoinAndSelect('article.classify','classify');
    }
    if(sort&&sort==='view') {
      queryBuilder.addOrderBy('article.view','DESC');
    }
    queryBuilder.addOrderBy('article.sort','DESC').addOrderBy('article.create_time','DESC');
    if(classifyId) {
      queryBuilder.andWhere("article.classify_id = :classifyId",{classifyId});
    }
    if(title) {
      queryBuilder.andWhere("article.title Like :title",{title:`%${title}%`});
    }
    if(tagId) {
      const tag = await this.tagRepository.createQueryBuilder('tag').leftJoinAndSelect('tag.articles','article').andWhere("tag.id = :tagId",{tagId}).getMany();
      const articleIds:Array<number> = [];
      for(const i of tag[0].articles) {
        articleIds.push(i.id);
      }   
      queryBuilder.andWhere("article.id In (:...articleIds)",{articleIds});
    }
    if(!page) {
      page = 1;
    }
    if(!limit) {
      limit = 10;
    }
    queryBuilder.take(limit).skip((page-1)*limit);
    const list = await queryBuilder.getManyAndCount();
    return ResultUtils.success({
      list:list[0],
      total:list[1]
    });
  }

  async findOne(id: number,isAdmin:boolean) {
    const queryBuilder = this.articleRepository.createQueryBuilder('article');
    if(!isAdmin) {
      queryBuilder.leftJoinAndSelect('article.tags','tag','tag.status = :status',{status:1})
                  .leftJoinAndSelect('article.classify','classify','classify.status = :status',{status:1})
                  .andWhere('article.status=:status',{status:1});
      await this.addView(id);            
    }else{
      queryBuilder.leftJoinAndSelect('article.tags','tags')
                  .leftJoinAndSelect('article.classify','classify');
    }
    queryBuilder.andWhere("article.id = :id",{id});
    return ResultUtils.success(await queryBuilder.getOne());
  }

  async update(id: number, updateArticleDto: UpdateArticleDto) {
    const article = await this.articleRepository.findOne({ where: {id}});
    if(updateArticleDto.tags instanceof Array && typeof updateArticleDto.tags[0] === 'number') {
      updateArticleDto.tags = await this.tagRepository.find({
        where:{
          id:In(updateArticleDto.tags as Array<number>)
        }
      });
    }
    if(typeof updateArticleDto.classify === 'number') {
      updateArticleDto.classify = await this.classifyRepository.findOne({
        where:{id:updateArticleDto.classify}
      });
    }
    const newArticle = this.articleRepository.merge(article,updateArticleDto as Partial<Article>);
    return ResultUtils.success(await this.articleRepository.save(newArticle));
  }

  async addView(id: number) {
    const article = await this.articleRepository.findOne({ where: {id}});
    article.view++;
    return await this.articleRepository.save(article);
  }

  async remove(id: number) {
    await this.articleRepository.delete(id);
    return ResultUtils.success();
  }
}
